#include <halintdist.h>
#include <printk.h>
#include <infointrpt.h>
#include <cpu_t.h>
#include <list.h>
#include <krlintrpt_t.h>

/*********************************************************************************
* 
* hal_dbug_print_reg - 
* 
* DESCRIPTION
*/

static void hal_dbug_print_reg 
    (
    cpuregs_t * cpuregs
    )
    {
    kprintf ("user_reg r0:%x\r\n", cpuregs->r0);

    return;
    }

/*********************************************************************************
 * 
 * hal_undefined_distribute - 
 * 
 * DESCRIPTION
 */

void hal_undefined_distribute (void * sframe)
    {
    hal_system_is_die ("undefined running!\r\n");
    return;
    }

/*********************************************************************************
 * 
 * hal_swi_distribute - 
 * 
 * DESCRIPTION
 */

sysstus_t hal_swi_distribute (uint_t swinbr, void * sframe)
    {
    sysstus_t status;

    status = syc_service_run (swinbr, sframe);   /* 调用内核相关的服务代码 */

    return status;
    }

/*********************************************************************************
 * 
 * hal_preincabort_distribute - 
 * 
 * DESCRIPTION
 */

void hal_preincabort_distribute (void * sframe)
    {
    hal_system_is_die ("pretreatment instruction abort running!\r\n");
    return;
    }

/*********************************************************************************
 * 
 * hal_dataabort_distribute - 
 * 
 * DESCRIPTION
 */

void hal_dataabort_distribute (void * sframe)
    {
    hal_system_is_die ("data abort running!\r\n");
    return;
    }

/*********************************************************************************
 * 
 * hal_irq_distribute - 中断源分发
 * 
 * DESCRIPTION
 */

void hal_irq_distribute (void * sframe)
    {

    /* 获取主中断源偏移寄存器 */

    uint_t intnbr = intrpt_return_irqnbr ();

    /* 依次判断和处理 子中断和外部中断 */

    switch (intnbr)
        {
        case INTOFST_EINT4_7:
            intdist_eint_distribute (sframe, intnbr, INTOFST_EINT4_7_S, INTOFST_EINT4_7_E);
            break;

        case INTOFST_EINT8_23:
            intdist_eint_distribute (sframe, intnbr, INTOFST_EINT8_23_S, INTOFST_EINT8_23_E);
            break;

        case INTOFST_INT_CAM:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_CAM_S, INTOFST_INT_CAM_E);
            break;

        case INTOFST_INT_WDT_AC9:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_WDT_AC9_S, INTOFST_INT_WDT_AC9_E);
            break;

        case INTOFST_INT_UART2:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_UART2_S, INTOFST_INT_UART2_E);
            break;

        case INTOFST_INT_UART1:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_UART1_S, INTOFST_INT_UART1_E);
            break;

        case INTOFST_INT_UART0:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_UART0_S, INTOFST_INT_UART0_E);
            break;

        case INTOFST_INT_ADC:
            intdist_sint_distribute (sframe, intnbr, INTOFST_INT_ADC_S, INTOFST_INT_ADC_E);
            break;

        default:
            intdist_mint_distribute (sframe, intnbr);
            break;
        }

    /* 清除主中断源挂起寄存器中的相关位 */

    intrpt_clear_irqsrcpnd (MAJINT_DESCIDX (intnbr));

    /* 检查进程调度标志和内核可抢占标志 */

    krl_sched_check_schedstus ();

    hal_system_is_die ("irq running!\r\n");
    return;
    }

/*********************************************************************************
 * 
 * hal_frq_distribute - 快速中断源分发
 * 
 * DESCRIPTION
 */

void hal_frq_distribute (void * sframe)
    {
    hal_system_is_die ("frq running!\r\n"); /* 不支持frq中断 */
    return;    
    }

/*********************************************************************************
 * 
 * intdist_mint_distribute - 主中断源分发
 * 
 * DESCRIPTION
 */

void intdist_mint_distribute 
    (
    void * sframe, 
    uint_t intnbr
    )
    {
    intdist_run_isrhandle (sframe, MAJINT_DESCIDX (intnbr));
    intrpt_clear_irqsrcpnd (MAJINT_DESCIDX (intnbr));
    return;
    }

/*********************************************************************************
 * 
 * intdist_eint_distribute - 外部中断源分发
 * 
 * DESCRIPTION
 */

void intdist_eint_distribute 
    (
    void * sframe, 
    uint_t intnbr, 
    uint_t ofststart, 
    uint_t ofstend
    )
    {
    u32_t i;
    u32_t pnd = hal_io32_read (S3C2440_REG_EINTPEND); /* 读取外部中断源挂起寄存器 */
    pnd &= EINTPND_BITS_MASK;                         /* 屏蔽掉无关的位 */

    for (i = ofststart; i < ofstend; i++)
        {
        
        /* 确定外部中断的中断源 */

        if (((pnd >> i) & 1) != 0)
            {
            intdist_run_isrhandle (sframe, EXTINT_DESCIDX (intnbr));
            intrpt_clear_irqsrcpnd (EXTINT_DESCIDX (i));   /* 清除该中断 */
            }
        }

    return;
    }

/*********************************************************************************
 * 
 * intdist_sint_distribute - 子中断源分发
 * 
 * DESCRIPTION
 */

void intdist_sint_distribute 
    (
    void * sframe, 
    uint_t intnbr, 
    uint_t ofststart, 
    uint_t ofstend
    )
    {
    u32_t i;
    u32_t pnd = hal_io32_read (S3C2440_REG_SUBSRCPND); /* 读取子中断源挂起寄存器 */
    pnd &= SINTPND_BITS_MASK;                          /* 屏蔽掉无关的位 */

    for (i = ofststart; i < ofstend; i++)
        {
        
        /* 确定子中断的中断源 */

        if (((pnd >> i) & 1) != 0)
            {
            intdist_run_isrhandle (sframe, SUBINT_DESCIDX (intnbr));
            intrpt_clear_irqsrcpnd (SUBINT_DESCIDX (i));   /* 清除该中断 */
            }
        }    


    return;
    }


/*********************************************************************************
 * 
 * intdist_run_isrhandle - 中断处理
 * 
 * DESCRIPTION
 */

void intdist_run_isrhandle
    (
    void * sframe,
    uint_t ifdidx
    )
    {
    intsrcdsc_t * intsrcdsc;
    intisrdsc_t * intisrdsc;
    list_t *      list;

    /* 获得中断源描述符 */

    intsrcdsc = intrpt_return_intsrcdsc (ifdidx);

    if (intsrcdsc == NULL)
        {
        hal_system_is_die ("intdist_run_isrhandle err\r\n");
        return;
        }

    /* 执行所有因该中断源触发需要执行的中断处理函数 (设备共用一个中断源) */

    list_for_each (list, &intsrcdsc->isrlist);
        {
        intisrdsc = list_entry (list, intisrdsc_t, list);
        intisrdsc->handle (ifdidx, intisrdsc->device, sframe);
        }

    return;
    }

